


import ikelib.wintime;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;

import wcg.CSVReader;
import wcg.ImportData;


/**
 * ＣＳＶをインポートするクラス
 *  パラメータをセットして、ＣＳＶファイルを指定し、ImportDataを作成する
 * @author ikechan
 *
 */
public class CsvImport {
	
	private int IgnoreHeadCount = 4; // 読み飛ばす行数
	private int TimeIndex = -1;
	private int TimeDiffIndex = 0; // TimeIndexは時間経過を表す
	private int Samplerate=1; // サンプルレート
	private String Delimiter = ",";
	private String StartTime = "2013/1/1 0:00:0"; // 時刻が指定されない場合の、最初の時間
	private int DataInterval = 60; // 時刻のない場合のデータ間隔
	private int InterporationMode = 0;
	/**
	 * CSVインポートのうち、CH毎のパラメータ
	 * Column , ChID, Factorなど
	 * @author ikechan
	 *
	 */
	public class CsvImportChElement {
		public int    Column=0;
		public int    Chid =0;
		public double Factor=0.0;
	}


	private LinkedList<Integer> DataColumn = new LinkedList<Integer>();
	private LinkedList<CsvImportChElement> Param = new LinkedList<CsvImportChElement>();
	
	CsvImport(){
	}
	/**
	 * パラメータをセットする。
	 * 
	 * @param starttime　Stringの時刻
	 * @param interval　CSVファイルの行間の秒数（時刻、時間指定がない場合）　
	 * @param intapomode　　インターぽレーションモード　
	 * @return
	 */
	public boolean setParameter2(String starttime,int interval,int intapomode){
		StartTime = new String(starttime);
		DataInterval = interval;
		InterporationMode = intapomode;
		return true;
	}
	/**
	 * パラメータをセットする
	 * @param p　追加したいパラメータ　CsvImportParameter で受け渡す
	 * @param cur　CONFIG名
	 * @return　boolean 成功・不成功
	 */
	public boolean setParameter(CsvImportParameter p,String cur){
		CsvImportParameter.CsvImportConfigElement   c = p.getConfig(cur); 
		if(c==null) return false;
		TimeIndex 		= c.DateColumn-1;
		TimeDiffIndex 	= c.IntervalColumn-1;
		Samplerate 		= c.SampleRate;
		IgnoreHeadCount = c.IgnoreHeader;
		Param.clear();
		Iterator<CsvImportParameter.CsvImportFieldElement> ite = c.Field.iterator();
		while(ite.hasNext()){
			CsvImportParameter.CsvImportFieldElement ele = ite.next();
			CsvImportChElement pele = new CsvImportChElement();
			pele.Chid = ele.Chid;
			pele.Column= ele.Column-1;
			pele.Factor = ele.Factor;
			Param.add(pele);
			DataColumn.add(pele.Column);
		}
		return true;
	}
	/**
	 * getter of Ignore header count
	 *  無視する最初の行数
	 * @return
	 */
	public int getIgnoreHeadCount() {
		return IgnoreHeadCount;
	}
	/**
	 * Setter of Ingore Head count
	 *  無視する最初の行数
	 * @param ignoreHeadCount
	 */
	public void setIgnoreHeadCount(int ignoreHeadCount) {
		IgnoreHeadCount = ignoreHeadCount;
	}
	/**
	 * Getter of timeIndex
	 *  時刻を示すカラムのインデックス　1,2,3,..
	 * @return timeIndex
	 */
	public int getTimeIndex() {
		return TimeIndex;
	}
	/**
	 * Setter of timeIndex
	 *  時刻を示すカラムのインデックス　1,2,3,..
	 * @param timeIndex
	 */
	public void setTimeIndex(int timeIndex) {
		TimeIndex = timeIndex;
	}
	/**
	 * Getter of timeDiffIndex
	 *  時間差を示すカラムのインデックス 1,2,3,..
	 * @return
	 */
	public int getTimeDiffIndex() {
		return TimeDiffIndex;
	}
	/**
	 * Setter of timeDiffIndex 
	 *  時間差を示すカラムのインデックス 1,2,3,..
	 * @param timeDiffIndex
	 */
	public void setTimeDiffIndex(int timeDiffIndex) {
		TimeDiffIndex = timeDiffIndex;
	}
	/**
	 * Getter of Samplerate
	 * @return
	 */
	public int getSamplerate() {
		return Samplerate;
	}
	/**
	 * サンプルレートのSetter
	 * @param samplerate
	 */
	public void setSamplerate(int samplerate) {
		Samplerate = samplerate;
	}
	/**
	 * ImportDataを得るテスト
	 * @return
	 */
	public ImportData getImportDataTest(){
		ImportData data = new ImportData();
		int[] d = new int[100*10];
		for(int i=0;i<d.length;i++){
			d[i] = i;
		}
		data.SetStartTime("2013/01/23 13:45:59");
		data.AddData(0x1234,d, 100);
		int[] d2 = new int[100*10];
		for(int i=0;i<d2.length;i++){
			d2[i] = 100-i;
		}
		data.AddData(0x1235,d2, 100);
		return data;
	}
	
	/**
	 * CSVファイル名からImportDataを作る。
	 * ＣＳＶファイルを開いて、データを作成する。
	 * @param csvfile
	 * @return　失敗するとnullを返す
	 */
	public ImportData getImportData(String csvfile){
		ImportData data = new ImportData();
		data.SetStartTime(StartTime);
		LinkedList<String[]> lst = new LinkedList<String[]>();
		FileReader fr;
		try {
			fr = new FileReader(csvfile);
			CSVReader csvr = new CSVReader(fr);
			csvr.setIgnoreHeader(IgnoreHeadCount);
			lst = csvr.getStringList();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		
		try {
			if(!makeData(data,lst)) return null;
		}
		
		catch (NumberFormatException e){  
			return null;
		}
		return data;
	}
	/**
	 * データをインターポレートする
	 * @param mode 0:Step&hold 1:Liner
	 * @param s1  データ　時間的に早い　（文字列）
	 * @param s2　データ　（文字列）
	 * @param num　補完する数
	 * @return　double[] インターポレートされたデータ
	 * @throws NumberFormatException
	 */
	private double[] interporateData(int mode,String s1,String s2,int num) throws NumberFormatException {
		double[] data = new double[num];
		
		double d1 = Double.valueOf(s1);
		double d2 = Double.valueOf(s2);
		if(mode==0){	// Step&Hold 
			for(int i=0;i<num;i++){
				data[i] = d1;
			}
		}
		else {	// 直線補完
			double delta = (d2-d1)/num;
			for(int i=0;i<num;i++){
				data[i] = d1 + delta*i;
			}
		}
		return data;
	}
	/**
	 * 指定column の　ＣＨパラメータを得る
	 * @param column
	 * @return
	 */
	private CsvImportChElement getParam(int column){
		Iterator<CsvImportChElement> ite  = Param.iterator();
		while(ite.hasNext()){
			CsvImportChElement p = ite.next();
			if(p.Column==column){
				return p;
			}
		}
		return null;
	}
	/*
	 * 
	 */
	/**
	 * double[]をint[]にパラメータにしたがって変換する。
	 * @param ddata　入力データ　
	 * @param column　列の番号 1,2,..
	 * @return 出力データ
	 */
	private int[] convData(double[] ddata,int column){
		CsvImportChElement p = getParam(column);
		if(p==null) return null;
		int[] ret = new int[ddata.length];
		for(int i=0;i<ddata.length;i++){
			ret[i] = (int)(ddata[i]*p.Factor);
		}
		return ret;
	}
	/*
	 * 
	 */
	/**
	 * データを作成する
	 * @param data　セット対象するデータ
	 * @param list　CSVファイルの行データ
	 * @return　boolean 成功、不成功
	 * @throws NumberFormatException　
	 */
	private boolean makeData(ImportData data,LinkedList<String[]> list) throws NumberFormatException {

		LinkedList<LinkedList<double[]>> datalist = new LinkedList<LinkedList<double[]>>();
		int totalDataNum=0; // 時間軸上のデータ数

		Iterator<String[]> ite = list.iterator();
		wintime wt1 = null;
		wintime wt2 = null;
		String[] s1=null;
		String[] s2=null;
		int count=0;
		while(ite.hasNext()){
			s1 = ite.next();
			if(count++ ==0){
				if(TimeIndex>=0){	// 時刻がそれぞれのデータにある場合
					if(!data.SetStartTime(s1[TimeIndex])) return false;
				}
				else{	
					if(!data.SetStartTime(StartTime)) return false;
				}
				Iterator<Integer> itecol = DataColumn.iterator();
				while(itecol.hasNext()){
					int col = itecol.next();
					// データリストのリストを作成しておく
					LinkedList<double[]> l = new LinkedList<double[]>();
					datalist.add(l);
				}
			}
			else{
				int intval=1;
				if(TimeIndex>=0){	// 時刻がそれぞれのデータにある場合
					wt1 = new wintime();
					wt1.setTime(s1[TimeIndex]);
					wt2 = new wintime();
					wt2.setTime(s2[TimeIndex]);
					// 直前の行との時間差（秒）
					intval = wt1.getValueS() - wt2.getValueS();
				}
				else if(TimeDiffIndex>=0){ // 時間差がそれぞれのデータにある場合
					intval = Integer.valueOf(s1[TimeDiffIndex]) - Integer.valueOf(s2[TimeDiffIndex]);
				}
				else{	// 時刻、時間差は指定されていいない
					intval = DataInterval;
				}
				
				// データの数
				int datanum = intval * Samplerate;
				totalDataNum += datanum;
				int index=0;
				Iterator<Integer> itecol = DataColumn.iterator();
				while(itecol.hasNext()){
					int col = itecol.next();
					double[] d = interporateData(InterporationMode ,s2[col],s1[col],datanum);
					// 指定のリストを得て
					LinkedList<double[]> l = datalist.get(index++);
					// 追加
					l.add(d);
				}
			}
			s2 = s1;
		}
			
		// doubleのデータリストのデータリストからint[]のリストを作る
		Iterator<Integer> itecol = DataColumn.iterator();
		int index = 0;
		while(itecol.hasNext()){
			int col = itecol.next();
			LinkedList<double[]> dl=datalist.get(index++);
			Iterator<double[]> ited = dl.iterator();
			double [] idata = new double[totalDataNum];
			int ccc = 0;
			while(ited.hasNext()){
				double[] d = ited.next();
				System.arraycopy(d,0,idata,ccc,d.length);
				ccc += d.length;
				
			}
			int[] iary  = convData(idata,col);
			CsvImportChElement p = getParam(col);
			if(p!=null){
				data.AddData(p.Chid, iary, Samplerate);
			}
		}
		return true;
	}
}
